package threaddemo9;

/**
 * Created by L.jp
 * Description:
 * User: 86189
 * Date: 2022-08-06
 * Time: 21:26
 */
/*案例需求
    电影院目前正在上映国产大片，共有100张票，而它有3个窗口卖票，请设计一个程序模拟该电影院卖票

实现步骤
    定义一个类SellTicket实现Runnable接口，里面定义一个成员变量：private int tickets = 100;
    在SellTicket类中重写run()方法实现卖票，代码步骤如下
        判断票数大于0，就卖票，并告知是哪个窗口卖的
        卖了票之后，总票数要减1
        票卖没了，线程停止
        定义一个测试类SellTicketDemo，里面有main方法，代码步骤如下
            创建SellTicket类的对象
            创建三个Thread类的对象，把SellTicket对象作为构造方法的参数，并给出对应的窗口名称
            启动线程
*/
//使用卖票案例演示同步代码块解决数据安全问题
public class SellTicket implements Runnable{
    //定义初始票数
    private int ticket=100;
    private final Object object=new Object(); //锁对象
    @Override
    public void run() {
        /*但是这个代码存在问题，因为ticket是共享变量，线程是并发的，
        如果不人为控制顺序执行抢票就会产生多个窗口剩余票数一样，甚至出现负票的情况，线程调度的时间是不确定的
        所以必须控制代码块让线程分别顺序执行他，这就是synchronized同步代码块，把操作共享数据的代码锁起来*/
//        while (true) {
//            //判断，如果票数小于等于0就停止售卖
//            if (ticket <= 0) {
//                break;
//            }else{
//                //正常的出票需要时间
//                try {
//                    Thread.sleep(500);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                //售票后票数--
//                ticket--;
//                //打印窗口还剩多少张、
//                System.out.println(Thread.currentThread().getName()+"在卖票，还剩"+ticket+"张");
//            }
//        }
    
        while (true) {
            //进了同步代码块就加锁，出了就解锁
            synchronized (object) {  //多个线程使用同一把锁
                //判断，如果票数小于等于0就停止售卖
                if (ticket <= 0) {
                    break;
                } else {
                    //正常的出票需要时间
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //售票后票数--
                    ticket--;
                    //打印窗口还剩多少张、
                    System.out.println(Thread.currentThread().getName() + "在卖票，还剩" + ticket + "张");
                }
            }
        }
    }
}
